1T_디버깅(Debugging), 오류(errors), 예외(Exceptions)처리(Handling)


In [1]:
for i in range(3):
    a = i * 7 #0, 7, 14
    b = i + 2 #2, 3, 4
    c = a * b # 0, 21, 56
#만약 이 range값이 3017, 5033일 경우에는 무슨 값인지 알 수 없다. 이 때 쉽게 a,b,c값이 무엇인지 찾는 방법을 소개
  • 디버깅? de+bugg+ing => 버그를 잡는다

  • Jupyter는 Python interpreter이다. 이것을 웹 환경에서 쓸 수 있도록 바꾼 것이 Jupyter Notebook 이다.

  • 예전 이름은 Ipython이었다.
  • 실제 환경(cmd에서 python 입력한 환경)에서는 tap키가 안 된다. 그래서 작성하기 어려운 환경이다.
  • Jupyter Notebook => Multi-user => Jupyterhub. 주피터 노트북은 멀티유저모드로 주피터허브라고 한다. 여러 사람이 같이 쓸 수 있는 환경
  • 디버깅은 IPython에 내장되어 있는 기능

In [2]:
name = "KiPyo Kim"
age = 29

from IPython import embed
embed()


In [1]: 기표

In [2]: 입니다.

In [3]: 어떻게

In [4]: 나가죠?

In [5]: exit


In [4]:
for i in range(3):
    a = i * 7 
    b = i + 2 
    c = a * b
    
    embed()


In [1]: print(a), print(b), print(c)
0
2
0

In [2]: exit


In [1]: print(a), print(b), print(c)
7
3
21

In [2]: exit


In [1]: print(a), print(b), print(c)
14
4
56

In [2]: exit


In [5]:
from IPython import embed; embed()   #보통 디버깅 할 때 이렇게 해서 단축키로 지정하고 많이 쓴다.


In [1]: exit()


In [ ]:
for i in range(100):
    from IPython import embed; embed()
#이렇게 하면 무한루프에 빠진다. 커널을 종료하는 수밖에...
  • 만약 안에 있는 것을 exit()로 종료하지 않고 dd로 밖에서 강제 종료할 경우
  • 계속 돌아가기 때문에 다음 명령어가 *에서 멈춘다. 그래서 노트북을 종료하고 재시작해야 한다.
  • embed는 IPython 내부에서 IPython을 또 띄운 것
  • Ipython embed가 디버깅 할 때 가장 많이 사용할 방법이다.일반적으로 사용

In [8]:
def fibo(n):
    if n <= 0:
        return 0
    if n == 1:
        return 1
    embed()
    return fibo(n-1) + fibo(n-2)

In [16]:
fibo(5)


In [1]: print(n)
5

In [2]: exit()


In [1]: print(n)
4

In [2]: exit()


In [1]: print(n)
3

In [2]: exit()


In [1]: print(n)
2

In [2]: exit()


In [1]: print(n)
2

In [2]: exit()


In [1]: print(n)
3

In [2]: exit()


In [1]: exit()

Out[16]:
5

In [1]:
class Student():
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def introduce(self):
        from IPython import embed; embed()
        return (self.name, self.age)

In [2]:
kkp = Student("kipoy", 29)

In [3]:
kkp.introduce()


In [1]: print(self)
<__main__.Student object at 0x000000000ADAF9B0>

In [2]: print(name)

In [3]: print(age)

In [4]: print(self.name)
kipoy

In [5]: print(self.age)
29

In [6]: exit()

Out[3]:
('kipoy', 29)

In [4]:
def fibo(n):
    if n <= 0:
        return 0
    if n == 1:
        return 1
    print("fibo({n}) = fibo({n_1}) + fibo({n-2})".format(n=n, n_1=n-1, n_2=n-2))
    return fibo(n-1) + fibo(n-2)

In [5]:
fibo(3)


---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-5-fceb215ca5a1> in <module>()
----> 1 fibo(3)

<ipython-input-4-f40970e5b46e> in fibo(n)
      4     if n == 1:
      5         return 1
----> 6     print("fibo({n}) = fibo({n_1}) + fibo({n-2})".format(n=n, n_1=n-1, n_2=n-2))
      7     return fibo(n-1) + fibo(n-2)

KeyError: 'n-2'

In [6]:
fibo(10)


---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-39a78796dcde> in <module>()
----> 1 fibo(10)

<ipython-input-4-f40970e5b46e> in fibo(n)
      4     if n == 1:
      5         return 1
----> 6     print("fibo({n}) = fibo({n_1}) + fibo({n-2})".format(n=n, n_1=n-1, n_2=n-2))
      7     return fibo(n-1) + fibo(n-2)

KeyError: 'n-2'
  • print를 쓰면 직관적으로 볼 수 있지만 안 좋은 이유는 결과에 영향을 미치기 때문
  • 그리고 특정값만 보고 싶은데 전체를 봐야 하기 때문에
  • (print는 결과에 영향을 안 미치지 않나?) -> 결과값에 영향이 아니라 output에 영향을 준다는 의미

  • 출력을 하기는 한다. 다만, print로 직접 하지는 않는다.
  • 로그를 쌓는다. ( Log ) -> logging

In [7]:
import logging

In [8]:
# logging -> debug, info, warning, danger, critical...
logging.warning("hello world")
  • cmd에서 python으로 실행할 경우에는 바로 WARNING이 뜬다.
  • 그런데 여기서 바로 안 뜨는 이유는 관리자로 봐야 하기 때문에
  • 주피터 노트북이 돌아가는 웹서버or관리창에 워닝이 기록된다.
  • 데이터분석은 로깅을 쓰는 것보다는 프린터를 쓰는 것이 더 낫다.
  • 머신러닝 프로젝트의 경우 장기적이거나 할 경우에는 로깅 형태가 낫다. 기록을 해 두는 것이 좋다.

오류에 대해서


In [9]:
name #뒤에 따라 오는 주석들 Traceback 이 있다.


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-9-03f01e0df6ef> in <module>()
----> 1 name #뒤에 따라 오는 주석들 Traceback 이 있다.

NameError: name 'name' is not defined
  • Error
    • 실행 자체가 되지 않은 것
    • 문법 자체의 오류가 있어서 SyntaxError ( ParsingError )

In [10]:
if True
     print("hello world")


  File "<ipython-input-10-1be06a9a3baf>", line 1
    if True
           ^
SyntaxError: invalid syntax
  • 오류에는 2가지가 있다.
    • SyntaxError와 SyntaxError가 아닌 것(Exceptions)

In [11]:
ab


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-daa8075d6ac5> in <module>()
----> 1 ab

NameError: name 'ab' is not defined

In [12]:
def error(a, b):
    a = b + 1
    print(a)
error


Out[12]:
<function __main__.error>

In [13]:
2 + "김기표"


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-c258396fe5b4> in <module>()
----> 1 2 + "김기표"

TypeError: unsupported operand type(s) for +: 'int' and 'str'

In [14]:
{}["somtthing"]


---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-14-59cc51b1c677> in <module>()
----> 1 {}["somtthing"]

KeyError: 'somtthing'

In [15]:
{}.append()


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-15-da1c3f58f6bf> in <module>()
----> 1 {}.append()

AttributeError: 'dict' object has no attribute 'append'

In [16]:
with open("./not_exist_file", "r") as f:
    pass


---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-16-a97a5d2f3a24> in <module>()
----> 1 with open("./not_exist_file", "r") as f:
      2     pass

FileNotFoundError: [Errno 2] No such file or directory: './not_exist_file'
  • Exception이 뜨면 좋은 것이다. 일단 남이 의도하지 않은 방향대로 뭔가 클래스나 함수, 객체 등을 쓰고 있는 것이기 때문

2T_예외를 처리하는 방법

  • Exception Handling

    • 예외를 처리하는 방법 => AttributeError, FileNotFoundError, AttributeError, ...
  • 우리가 직접 예외를 만드는 방법(FibonacciShouldGetPositiveNumberError => 우리만의 예외)

    • Class를 만들어야 한다.

In [17]:
NameError


Out[17]:
NameError

In [18]:
Exception?

In [19]:
def append_string_to_hello(string):
    return "hello, " + string

In [20]:
append_string_to_hello("world")


Out[20]:
'hello, world'

In [21]:
append_string_to_hello(13)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-3a0c67a7fc20> in <module>()
----> 1 append_string_to_hello(13)

<ipython-input-19-4c38bfd9a769> in append_string_to_hello(string)
      1 def append_string_to_hello(string):
----> 2     return "hello, " + string

TypeError: Can't convert 'int' object to str implicitly

In [22]:
"hello, " + 3
#str + int, implicit(함축적)한 방법이다.
#Python은 형변환이 되지 않기 때문이다.(형변환 잘 되는 것은 루비)
#자유도가 높거나 해서 좋은 언어는 아니다. 언어 특성에 맞게 사용하면 된다.


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-28b93a0c5c1e> in <module>()
----> 1 "hello, " + 3
      2 #str + int, implicit(함축적)한 방법이다.
      3 #Python은 형변환이 되지 않기 때문이다.(형변환 잘 되는 것은 루비)
      4 #자유도가 높거나 해서 좋은 언어는 아니다. 언어 특성에 맞게 사용하면 된다.

TypeError: Can't convert 'int' object to str implicitly

In [23]:
"hello" + str(3)
# str + str(int), explicit(명시적)한 방법이다.


Out[23]:
'hello3'

In [24]:
awesome_list = ["world", "hello", "python", 5678, "fastcampus"]

for awesome in awesome_list:
    # 예외 처리가 가능한 장소 [1] => 밑에 있는 케이스에서만 예외처리가 가능
    print(append_string_to_hello(awesome))


hello, world
hello, hello
hello, python
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-cd93c34e12eb> in <module>()
      3 for awesome in awesome_list:
      4     # 예외 처리가 가능한 장소 [1] => 밑에 있는 케이스에서만 예외처리가 가능
----> 5     print(append_string_to_hello(awesome))

<ipython-input-19-4c38bfd9a769> in append_string_to_hello(string)
      1 def append_string_to_hello(string):
----> 2     return "hello, " + string

TypeError: Can't convert 'int' object to str implicitly

In [25]:
def append_string_to_hello(string):
    # 예외처리가 가능한 장소(2) => 함수 불렀을 모든 경우에서 예외 처리 가능
    # 그래서 2번에서 해보겠다.
    return "hello, " + string

In [28]:
def append_string_to_hello(string):
    # 예외처리가 가능한 장소
    # 예외처리 => try:-except: (항상 이런 방법으로 한다.)
    try:
        return "hello, " + string
    except TypeError as err:
        print("오류" * 40)

In [29]:
append_string_to_hello(123)


오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류오류

In [30]:
def append_string_to_hello(string):
    try:
        return "hello, " + string
    except TypeError as err:
        #TypeError는 class다. 즉 에러 하나하나 자체는 클래스로 만들어진 에러 객체이다.
        print(err)

In [31]:
append_string_to_hello(123)


Can't convert 'int' object to str implicitly

In [32]:
def append_string_to_hello(string):
    try:
        return "hello, " + string
    except TypeError as err:
        return err

In [33]:
append_string_to_hello(123)


Out[33]:
TypeError("Can't convert 'int' object to str implicitly")

In [34]:
def append_string_to_hello(string):
    try:
        return "hello, " + string
    except: #이렇게 할 경우 모든 에러에 대해 예외처리. 일반적으로 많이 사용
        return err

In [35]:
append_string_to_hello(123)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-34-a4a4d7810b5b> in append_string_to_hello(string)
      2     try:
----> 3         return "hello, " + string
      4     except: #이렇게 할 경우 모든 에러에 대해 예외처리. 일반적으로 많이 사용

TypeError: Can't convert 'int' object to str implicitly

During handling of the above exception, another exception occurred:

NameError                                 Traceback (most recent call last)
<ipython-input-35-91c519cdd2d5> in <module>()
----> 1 append_string_to_hello(123)

<ipython-input-34-a4a4d7810b5b> in append_string_to_hello(string)
      3         return "hello, " + string
      4     except: #이렇게 할 경우 모든 에러에 대해 예외처리. 일반적으로 많이 사용
----> 5         return err

NameError: name 'err' is not defined

In [36]:
def append_string_to_hello(string):
    try:
        return "hello, " + string
    except {TypeError, AttributeError} as err: #이렇게도 쓰나 잘 쓰진 않는다. 
        return err

In [37]:
append_string_to_hello(123)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-15b15af5ebba> in append_string_to_hello(string)
      2     try:
----> 3         return "hello, " + string
      4     except {TypeError, AttributeError} as err: #이렇게도 쓰나 잘 쓰진 않는다.

TypeError: Can't convert 'int' object to str implicitly

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-37-91c519cdd2d5> in <module>()
----> 1 append_string_to_hello(123)

<ipython-input-36-15b15af5ebba> in append_string_to_hello(string)
      2     try:
      3         return "hello, " + string
----> 4     except {TypeError, AttributeError} as err: #이렇게도 쓰나 잘 쓰진 않는다.
      5         return err

TypeError: catching classes that do not inherit from BaseException is not allowed

In [38]:
def append_string_to_hello(string):
    try:
        return "hello, " + string
    except TypeError as err:
        #알람을 받을 수 있도록 넣을수도 있다.
        print("send_sms")
        raise

In [39]:
append_string_to_hello(123)


send_sms
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-39-91c519cdd2d5> in <module>()
----> 1 append_string_to_hello(123)

<ipython-input-38-a344848aef44> in append_string_to_hello(string)
      1 def append_string_to_hello(string):
      2     try:
----> 3         return "hello, " + string
      4     except TypeError as err:
      5         #알람을 받을 수 있도록 넣을수도 있다.

TypeError: Can't convert 'int' object to str implicitly

In [40]:
def append_string_to_hello(string):
    try:
        return "hello, " + string
    except TypeError as err:
        print("send_sms")
        raise
    except AttributeError as err:
        pass

In [41]:
append_string_to_hello(123)


send_sms
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-41-91c519cdd2d5> in <module>()
----> 1 append_string_to_hello(123)

<ipython-input-40-227012a2ac7c> in append_string_to_hello(string)
      1 def append_string_to_hello(string):
      2     try:
----> 3         return "hello, " + string
      4     except TypeError as err:
      5         print("send_sms")

TypeError: Can't convert 'int' object to str implicitly

In [42]:
def append_string_to_hello(string):
    try:
        return "hello, " + string
    except TypeError as err:
        print("send_sms")
        print(err)
#         raise
    except AttributeError as err:
        pass
    finally:                #예외가 발생했던 아니던 어쨌든 실행하고 싶을 때
        print("어쨌던 끝남")

In [43]:
append_string_to_hello(123)


send_sms
Can't convert 'int' object to str implicitly
어쨌던 끝남

In [44]:
awesome_list = ["world", "hello", "python", 5678, "fastcampus"]

for awesome in awesome_list:
    print(append_string_to_hello(awesome))


어쨌던 끝남
hello, world
어쨌던 끝남
hello, hello
어쨌던 끝남
hello, python
send_sms
Can't convert 'int' object to str implicitly
어쨌던 끝남
None
어쨌던 끝남
hello, fastcampus

우리만의 예외처리 class를 만들어보겠다.


In [45]:
def fibo(x):
    if x < 0:
#         err = FibonacciShouldNotHaveNegativeNumberError()
#         raise err
        #일반적으로 위와 같은 2줄이 아닌 아래와 같은 1줄로 적는다.
    
        raise FibonacciShouldNotHaveNegativeNumberError()
    
    if x == 0:
        return 0
    if x == 1:
        return 1
    return fibo(x-1) + fibo(x-2)

In [46]:
#Exception Class
class FibonacciShouldNotHaveNegativeNumberError(Exception):
    
    def __init__(self):
        pass
  • 상속 순서
    • object -> Exception -> Fibo...

In [47]:
fibo(-1)


---------------------------------------------------------------------------
FibonacciShouldNotHaveNegativeNumberError Traceback (most recent call last)
<ipython-input-47-b967601a7d3d> in <module>()
----> 1 fibo(-1)

<ipython-input-45-dcc14b4ca3b6> in fibo(x)
      5         #일반적으로 위와 같은 2줄이 아닌 아래와 같은 1줄로 적는다.
      6 
----> 7         raise FibonacciShouldNotHaveNegativeNumberError()
      8 
      9     if x == 0:

FibonacciShouldNotHaveNegativeNumberError: 

In [48]:
raise FibonacciShouldNotHaveNegativeNumberError()   
# 다른 에러들은 수정 요구 사항까지 나온다.


---------------------------------------------------------------------------
FibonacciShouldNotHaveNegativeNumberError Traceback (most recent call last)
<ipython-input-48-ed8cdd0dae0b> in <module>()
----> 1 raise FibonacciShouldNotHaveNegativeNumberError()
      2 # 다른 에러들은 수정 요구 사항까지 나온다.

FibonacciShouldNotHaveNegativeNumberError: 

In [49]:
"hello, " + 5678
# 노란색 에러는 수정 요구 사항
# 이건 어디서 수정 가능하냐? def __str__(self): 여기서!


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-49-46a1a01018a4> in <module>()
----> 1 "hello, " + 5678
      2 # 노란색 에러는 수정 요구 사항
      3 # 이건 어디서 수정 가능하냐? def __str__(self): 여기서!

TypeError: Can't convert 'int' object to str implicitly

In [50]:
class FibonacciShouldNotHaveNegativeNumberError(Exception):
    
    def __init__(self):
        pass
    
    def __str__(self):
        return "피보나치 수열은 index 값으로 양수를 받아야 합니다"

In [51]:
raise FibonacciShouldNotHaveNegativeNumberError()


---------------------------------------------------------------------------
FibonacciShouldNotHaveNegativeNumberError Traceback (most recent call last)
<ipython-input-51-f61af54030ab> in <module>()
----> 1 raise FibonacciShouldNotHaveNegativeNumberError()

FibonacciShouldNotHaveNegativeNumberError: 피보나치 수열은 index 값으로 양수를 받아야 합니다

In [52]:
def fibo(x):
    if x < 0:
        raise FibonacciShouldNotHaveNegativeNumberError(x)
    if x == 0:
        return 0
    if x == 1:
        return 1
    return fibo(x-1) + fibo(x-2)

In [53]:
class FibonacciShouldNotHaveNegativeNumberError(Exception):
    
    def __init__(self, n):
        self.n = n
        
    def __str__(self):
        return "이 함수는 index 값으로 양수를 받아야 합니다. (입력받은 값: {n})".format(n=self.n)   #에러메세지 요구사항

In [54]:
fibo(-13)


---------------------------------------------------------------------------
FibonacciShouldNotHaveNegativeNumberError Traceback (most recent call last)
<ipython-input-54-9a72f08974a4> in <module>()
----> 1 fibo(-13)

<ipython-input-52-34b14e89b014> in fibo(x)
      1 def fibo(x):
      2     if x < 0:
----> 3         raise FibonacciShouldNotHaveNegativeNumberError(x)
      4     if x == 0:
      5         return 0

FibonacciShouldNotHaveNegativeNumberError: 이 함수는 index 값으로 양수를 받아야 합니다. (입력받은 값: -13)

예외처리를 포함하여,

Factorial 함수를 구현하세요. n! = n (n-1) (n-2) ... 2 * 1


In [55]:
def Factorial(n):
    if n == 1:
        return 1
    return n * Factorial(n-1)

In [56]:
Factorial(5)


Out[56]:
120

In [57]:
def Factorial(n):
    if n < 0:
        raise FactorialShouldGetPositiveIndexError(n)
    if n == 1:
        return 1
    return n * Factorial(n-1)

In [58]:
class FactorialShouldGetPositiveIndexError(Exception):
    def __init__(self, n):
        self.n = n
    
    def __str__(self):
        return "factorial function should get positive index. (input: {n})".format(n=self.n)

In [59]:
Factorial(-3)


---------------------------------------------------------------------------
FactorialShouldGetPositiveIndexError      Traceback (most recent call last)
<ipython-input-59-21d63656ce10> in <module>()
----> 1 Factorial(-3)

<ipython-input-57-19ab39e12839> in Factorial(n)
      1 def Factorial(n):
      2     if n < 0:
----> 3         raise FactorialShouldGetPositiveIndexError(n)
      4     if n == 1:
      5         return 1

FactorialShouldGetPositiveIndexError: factorial function should get positive index. (input: -3)

3T_Ubuntu - 기초 명령어

  • Vim ,Emacs 등의 에디터에 대한 개념
  • Shell -> bash shell(shell script) => 우분투에서 사용하는 기본 에디터

<우분투 개념>

  • 우분투는 짝수 버전으로 사용한다. 지금은 Ubuntu Server 14.04 trusty
  • trusty는 14.04. precise->12.04
  • 리눅스에는 Package Manager라는 강력한 커맨드가 있다.
  • 각각의 언어(파이썬, 루비, C...)에 Package Manager가 있다.
  • 우분투의 경우에는 이름이 apt-get이라는 Package Manager가 있다.

<우분투 관련 명령어>

  • clear
    • 위로 밀리면서 배경창 깨끗하게
  • echo "hello world"
    • 그대로 출력
  • ls
    • list. 안에 있는 파일과 폴더들을 볼 수 있다.
    • 옵션: -a(숨김파일을 볼 수 있다.), -al(list 형태로 상세 정보가 같이 출력)
  • mkdir dev
    • 폴더 만드는 명령어
  • cd
    • change directory. 디렉토리 이동하기
  • pwd
    • 현재 있는 위치를 알려줌. print working directory
  • cd .(현재 디렉토리) cd ..(상위 디렉토리로 이동)
  • touch
    • 파일을 만든다.
  • rm
    • 파일 및 폴더를 지운다.
  • rm -r
    • 해당 파일 안까지 다 지운다는 거. recursive하게 지운다는 의미
  • man
    • manual이라는 의미. man rm을 입력하면 메뉴얼이 나온다.

<우분투에서 pyenv 설치>

  • apt-get update
    • 이렇게만 하면 오류가 날 것이다.
  • sudo apt-get update
    • 내가 아니라 관리자 권한으로 apt-get update라는 명령어를 실행한다.